/***
 * @Description:基于TCP协议的实现echo功能的C语言文件
 * @Author: Liverpool
 * @Date: 2024-01-11 00:30:59
 * @LastEditTime: 2024-01-11 00:38:10
 * @LastEditors: Liverpool
 */
#include "tcp_echo_client.h"

/***
 * @description:基于TCP协议的echo客户端启动函数完成于服务器端的连接并获取键盘上的输入
 * @Author: Liverpool
 * @Date: 2024-01-11 00:38:16
 * @return {*} 启动是否成功
 * @param {char} *ip 需要连接的服务器端的IP地址
 * @param {int} port 该IP地址需要连接的端口号
 */
int tcp_echo_client_start(const char *ip, int port)
{
    plat_printf("tcp echo client, ip=%s port=%d\n", ip, port); // 打印需要连接的客户端IP地址和端口号

    WSADATA wsaData;                      // 需要进行相应的socket库绑定,使用Socket的程序在使用Socket之前必须调用WSAStartup函数
    WSAStartup(MAKEWORD(2, 2), &wsaData); // MAKEWORD是将两个byte型合并成一个word型，一个在高8位(b)，一个在低8位(a),使用WINSOCK2版本

    // 1.创建套接字
    SOCKET socket1 = socket(AF_INET, SOCK_STREAM, 0); // 使用IPv4协议 数据流的形式进行传输 0表示不使用协议
    if (socket1 == INVALID_SOCKET)                    // 获取的socket关键字不合法
    {
        plat_printf("tcp echo client:open socket error\n");
        goto end;
    }
    // 2.对需要连接的IP地址进行指定
    struct sockaddr_in server_addr; // 服务器端的IP地址
    plat_memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;            // 使用IPv4协议
    server_addr.sin_addr.s_addr = inet_addr(ip); // 把字符串IP地址变为整形 并赋给服务器IP地址结构体
    server_addr.sin_port = htons(port);          // 再intel机器上用的是小端编码 而在网络上的用的是大端存储 所以需要进行小端到大端的转换
    // 3 进行与服务器连接
    if (connect(socket1, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        // 如果连接不上就报错
        plat_printf("connect error\n");
        goto end;
    }
    // 4 再键盘上读取输入并且发送给服务器
    char buffer[128];
    plat_memset(&buffer, 0, sizeof(buffer)); // 清空buffer的数据
    plat_printf(">>>:");
    // 使用标准输入读取键盘的数据
    while (fgets(buffer, sizeof(buffer), stdin) != NULL)
    {
        // 像服务器发送键盘读取到的字符串
        if (send(socket1, buffer, (int)plat_strlen(buffer), 0) <= 0)
        {
            // 发送错误
            plat_printf("send error\n");
            goto end;
        }
        plat_memset(buffer, 0, sizeof(buffer));                 // 清除缓存区用来存服务器接收到的数据
        int len = recv(socket1, buffer, sizeof(buffer) - 1, 0); // 进行接收数据
        if (len <= 0)
        {
            plat_printf("recv error\n");
            goto end;
        }
        plat_printf("tcp echo client recv:%s\n", buffer);
        plat_printf(">>>:");
    }

end:
    // 5 关闭套接字
    if (socket1 != INVALID_SOCKET)
    {
        closesocket(socket1); // 关闭套接字
    }
    return -1;
}